import { Module } from 'vuex';
import { State } from '@/store';
import { _RouteLocationBase, RouteRecordName } from 'vue-router';
import {
  ADD_CACHED_VIEW,
  ADD_VISITED_VIEW,
  addCachedView,
  addView,
  addVisitedView,
  cachedViews,
  DEL_ALL_CACHED_VIEWS,
  DEL_ALL_VISITED_VIEWS,
  DEL_CACHED_VIEW,
  DEL_OTHERS_CACHED_VIEWS,
  DEL_OTHERS_VISITED_VIEWS,
  DEL_VISITED_VIEW,
  delAllCachedViews,
  delAllViews,
  delAllVisitedViews,
  delCachedView,
  delOthersCachedViews,
  delOthersViews,
  delOthersVisitedViews,
  delView,
  delVisitedView,
  UPDATE_VISITED_VIEW,
  updateVisitedView,
  visitedViews,
} from '@/store/modules/views/pool';

export type VisitedView = _RouteLocationBase;

export type CachedView = RouteRecordName | null | undefined;

export interface ViewState {
  visitedViews: VisitedView[];
  cachedViews: CachedView[];
}

export const views: Module<ViewState, State> = {
  namespaced: true,
  state: () => ({
    visitedViews: [],
    cachedViews: [],
  }),
  getters: {
    [visitedViews]: state => state.visitedViews,
    [cachedViews]: state => state.cachedViews,
  },
  mutations: {
    [ADD_VISITED_VIEW]: (state, view: _RouteLocationBase) => {
      if (state.visitedViews.every(v => v.path !== view.path)) {
        state.visitedViews.push(view);
      }
    },
    [ADD_CACHED_VIEW]: (state, view: _RouteLocationBase) => {
      if (state.cachedViews.includes(view.name) || view.meta.noCache) {
        return;
      }
      state.cachedViews.push(view.name);
    },
    [DEL_VISITED_VIEW]: (state, view: _RouteLocationBase) => {
      for (const [i, v] of state.visitedViews.entries()) {
        if (v.path === view.path) {
          state.visitedViews.splice(i, 1);
          break;
        }
      }
    },
    [DEL_CACHED_VIEW]: (state, view: _RouteLocationBase) => {
      const index = state.cachedViews.indexOf(view.name);
      index > -1 && state.cachedViews.splice(index, 1);
    },
    [DEL_OTHERS_VISITED_VIEWS]: (state, view: _RouteLocationBase) => {
      state.visitedViews = state.visitedViews.filter(v => {
        return v.meta.affix || v.path === view.path;
      });
    },
    [DEL_OTHERS_CACHED_VIEWS]: (state, view: _RouteLocationBase) => {
      const index = state.cachedViews.indexOf(view.name);
      if (index > -1) {
        state.cachedViews = state.cachedViews.slice(index, index + 1);
      } else {
        // if index = -1, there is no cached tags
        state.cachedViews = [];
      }
    },
    [DEL_ALL_VISITED_VIEWS]: state => {
      // keep affix tags
      state.visitedViews = state.visitedViews.filter(tag => tag.meta.affix);
    },
    [DEL_ALL_CACHED_VIEWS]: state => {
      state.cachedViews = [];
    },
    [UPDATE_VISITED_VIEW]: (state, view: _RouteLocationBase) => {
      for (let v of state.visitedViews) {
        if (v.path === view.path) {
          v = Object.assign(v, view);
          break;
        }
      }
    },
  },
  actions: {
    async [addView]({ dispatch }, view: _RouteLocationBase) {
      await dispatch(addVisitedView, view);
      await dispatch(addCachedView, view);
    },
    [addVisitedView]({ commit }, view: _RouteLocationBase) {
      commit(ADD_VISITED_VIEW, view);
    },
    [addCachedView]({ commit }, view: _RouteLocationBase) {
      commit(ADD_CACHED_VIEW, view);
    },
    async [delView]({ dispatch, state }, view: _RouteLocationBase) {
      await dispatch(delVisitedView, view);
      await dispatch(delCachedView, view);
      return {
        visitedViews: [...state.visitedViews],
        cachedViews: [...state.cachedViews],
      };
    },
    async [delVisitedView]({ commit, state }, view: _RouteLocationBase) {
      commit(DEL_VISITED_VIEW, view);
      return [...state.visitedViews];
    },
    async [delCachedView]({ commit, state }, view: _RouteLocationBase) {
      commit(DEL_CACHED_VIEW, view);
      return [...state.cachedViews];
    },
    async [delOthersViews]({ dispatch, state }, view: _RouteLocationBase) {
      dispatch(delOthersVisitedViews, view);
      dispatch(delOthersCachedViews, view);
      return {
        visitedViews: [...state.visitedViews],
        cachedViews: [...state.cachedViews],
      };
    },
    async [delOthersVisitedViews]({ commit, state }, view: _RouteLocationBase) {
      commit(DEL_OTHERS_VISITED_VIEWS, view);
      return [...state.visitedViews];
    },
    async [delOthersCachedViews]({ commit, state }, view: _RouteLocationBase) {
      commit(DEL_OTHERS_CACHED_VIEWS, view);
      return [...state.cachedViews];
    },
    async [delAllViews]({ dispatch, state }) {
      dispatch(delAllVisitedViews);
      dispatch(delAllCachedViews);
      return {
        visitedViews: [...state.visitedViews],
        cachedViews: [...state.cachedViews],
      };
    },
    async [delAllVisitedViews]({ commit, state }) {
      commit(DEL_ALL_VISITED_VIEWS);
      return [...state.visitedViews];
    },
    async [delAllCachedViews]({ commit, state }) {
      commit(DEL_ALL_CACHED_VIEWS);
      return [...state.cachedViews];
    },
    [updateVisitedView]({ commit }, view: _RouteLocationBase) {
      commit(UPDATE_VISITED_VIEW, view);
    },
  },
};
